﻿using System;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Sakura.Silverlight.Extensions
{
	[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
	public class CompareAttribute : ValidationAttribute
	{
		/// <summary>
		/// 获取或设置要比较的另一个属性的名称。
		/// </summary>
		public string OtherProperty
		{
			get;
			private set;
		}

		/// <summary>
		/// 获取或设置要和另一个属性进行比较的模式。
		/// </summary>
		public CompareMode CompareMode
		{
			get;
			private set;
		}

		/// <summary>
		/// 获取或设置要显示的另一个属性的显示名称。如果该属性为 <c>null</c> 则使用默认的显示名称。
		/// </summary>
		public string OtherPropertyDisplayName
		{
			get;
			set;
		}

		/// <summary>
		/// 用于进行比较的核心方法。
		/// </summary>
		/// <param name="value1">要比较的第一个值。</param>
		/// <param name="value2">要比较的第二个值。</param>
		/// <param name="mode">要比较的模式。</param>
		/// <returns>如果符合比较要求，返回 <c>true</c>；否则返回 <c>false</c>。</returns>
		public static bool CompareCore(object value1, object value2, CompareMode mode)
		{
			switch (mode)
			{
				case CompareMode.Equal:
					return object.Equals(value1, value2);
				case CompareMode.NotEqual:
					return !object.Equals(value1, value2);
				default:
					throw new InvalidOperationException(Resources.ExCompareModeInvalid);
			}
		}

		/// <summary>
		/// 确定值是否有效。
		/// </summary>
		/// <param name="value">要比较的值。</param>
		/// <param name="validationContext">比较的上下文。</param>
		/// <returns>比较的结果。</returns>
		protected override ValidationResult IsValid(object value, ValidationContext validationContext)
		{
			var otherProp = validationContext.ObjectType.GetProperty(this.OtherProperty);

			if (otherProp == null)
			{
				throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, Resources.ExComparePropertyNotAccessable, this.OtherProperty));
			}
			var otherValue = otherProp.GetValue(validationContext.ObjectInstance, null);

			if (CompareCore(value, otherValue, this.CompareMode))
			{
				return ValidationResult.Success;
			}
			else
			{
				this.InitializeOtherPropertyDisplayName(validationContext.ObjectType, this.OtherProperty);
				return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
			}
		}

		/// <summary>
		/// 根据模式获得错误字符串。
		/// </summary>
		/// <param name="mode">比较的类型。</param>
		/// <returns>错误字符串的内容。</returns>
		private static string GetErrorMessageString(CompareMode mode)
		{
			switch (mode)
			{
				case Extensions.CompareMode.Equal:
					return Resources.MsgCompareModeEqual;
				case Extensions.CompareMode.NotEqual:
					return Resources.MsgCompareModeNotEqual;
				default:
					throw new InvalidOperationException(Resources.ExCompareModeInvalid);
			}
		}

		/// <summary>
		/// 获得指定类型显示属性名称。
		/// </summary>
		/// <param name="containerType">容器类型。</param>
		/// <param name="propertyName">属性名称。</param>
		/// <returns>属性的显示名称。</returns>
		private static string GetDisplayNameForProperty(Type containerType, string propertyName)
		{
			var prop = containerType.GetProperty(propertyName);

			if (prop != null)
			{
				var attrs = prop.GetCustomAttributes(typeof(DisplayAttribute), true);
				
				if (attrs.Length == 1)
				{
					var attr = attrs[0] as DisplayAttribute;
					return attr.Name;
				}
			}

			return null;
		}

		/// <summary>
		/// 为另一个属性设定显示名称。
		/// </summary>
		/// <param name="containerType">容器类型。</param>
		/// <param name="propertyName">属性名称。</param>
		private void InitializeOtherPropertyDisplayName(Type containerType, string propertyName)
		{
			if (this.OtherPropertyDisplayName == null)
			{
				this.OtherPropertyDisplayName = GetDisplayNameForProperty(containerType, propertyName);
			}
		}

		/// <summary>
		/// 格式化信息字符串。
		/// </summary>
		/// <param name="name">属性名称。</param>
		/// <returns>错误字符串。</returns>
		public override string FormatErrorMessage(string name)
		{
			return this.FormatErrorMessage(name, this.OtherPropertyDisplayName);
		}

		/// <summary>
		/// 格式设置内容。
		/// </summary>
		/// <param name="thisName">当前属性名称。</param>
		/// <param name="otherName">比较属性名称。</param>
		/// <returns>错误字符串。</returns>
		private string FormatErrorMessage(string thisName, string otherName)
		{
			return string.Format(CultureInfo.CurrentUICulture, base.ErrorMessage, thisName, otherName);
		}

		/// <summary>
		/// 用指定的信息初始化一个特性的新实例。
		/// </summary>
		/// <param name="otherProperty">要比较的另一个属性的名称。</param>
		/// <param name="mode">比较的模式。</param>
		public CompareAttribute(string otherProperty, CompareMode mode)
			: base(GetErrorMessageString(mode))
		{
			this.OtherProperty = otherProperty;
			this.CompareMode = mode;
		}
	}
}
